﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IAD2
{
    class Kohonen : Algorithm
    {
        protected double neighbourhood_range;
        protected bool gaus, sleep;
        protected int sleep_time;
        protected int epoc=0;
        public Kohonen(Network net, List<Neuron> pattern, double n, double neighbourhood_range=0.5, bool gaus = false, int sleep = 0)
            : base(net, pattern, n)
        {
            this.neighbourhood_range = neighbourhood_range;
            this.gaus = gaus;
            if (sleep > 0)
                this.sleep = true;
            else
                this.sleep = false;
            this.sleep_time = sleep;
        }
        public override void action(int epocNumber, double eps = 0.0001)
        {
            Random random = new Random();
            do
            {
                int pattternNumber = random.Next(pattern.Count);
                net.sortNeuronsByDistance(pattern[pattternNumber]);
                net.sortNeuronsByDistance(net.points.First());
                if (this.sleep)
                    net.points.First().goSleep(sleep_time);

                foreach (Neuron tempNeuron in net.points)
                {
                    if (gaus)
                    {
                        tempNeuron.moveTo(pattern[pattternNumber], this.gausFunc(tempNeuron));
                    } else {
                        if (tempNeuron.Distance > this.neighbourhood_range)
                            continue;
                        tempNeuron.moveTo(pattern[pattternNumber], n);
                    }
                        
                    
                }
                
               if(epoc % 10 == 0)
                    this.createChart("koh-epoc" + epoc + ".png");
               epoc++;
            } while (net.diffLast() > eps  && epoc < epocNumber);
            
        }

        public double gausFunc(Neuron neuron)
        {
            return Math.Exp(-Math.Pow(neuron.Distance, 2)/(2*Math.Pow(this.neighbourhood_range, 2)));
        }

        public string getResult(){
            return epoc + " & " + net.countZombie() + " & " + this.n + " & " + this.neighbourhood_range + " & " + this.sleep_time + " \\\\ \\hline";
            
        }

        


    }
}
